<?php


namespace Modules\Common\General\Security\Authorization;


use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Modules\Common\General\Security\Api\Gateway;
use Modules\Common\General\Security\Authorization\Exceptions\AuthorizationMissingException;
use Modules\Common\Models\AdminPermission;
use Modules\Common\Util\Database;

class RestrictBranchForQuery
{
    public static function restrict()
    {
        if (2 === Gateway::AdminUser()->type) {
            //超级管理员，可以访问任何接口，且没有任何限制
            return true;
        } else {
            //普通管理员，需要验证权限
            //不在权限表中的接口普通管理员不能访问
            $path = app('router')->getRoutes()->match(\request())->uri;
            $currentRoutePermission = AdminPermission::where('path', '/' . $path)
                ->where('method', request()->method())
                ->first();
            if ($currentRoutePermission->disable == Database::BOOL_TRUE) {
                return true;
            }
            if (is_null($currentRoutePermission)) {
                AuthorizationMissingException::new()
                    ->tellUser('对不起，您没有权限访问该资源')
                    ->logNotice('缺少权限')
                    ->throw();
            } else {
                //哪些分公司已授权
                $authorizedBranches = self::getAuthorizedBranches($currentRoutePermission);
                if (!$authorizedBranches) {
                    AuthorizationMissingException::new()
                        ->tellUser('对不起，您没有权限访问该资源的任何数据')
                        ->logNotice('缺少权限')
                        ->throw();
                }
                //依次为模型添加全局作用域
                $modelClasses = array_merge(self::getHasBranchForeignKeyModels(), ['Modules\Common\Models\Branch']);
                foreach ($modelClasses as $class) {
                    $class::addGlobalScope('branch', function (Builder $query) use ($authorizedBranches) {
                        $tableName = $query->getModel()->getTable();
                        if ($query->getQuery()->joins) {
                            $query->whereIn("$tableName.branch_id", $authorizedBranches);
                        } else {
                            if ($tableName === 'branches') {
                                $query->whereIn('id', $authorizedBranches);
                            } else {
                                $query->whereIn('branch_id', $authorizedBranches);
                            }
                        }
                    });
                }
            }
        }
    }

    private static function getAuthorizedBranches($currentRoutePermission)
    {
        $userPermissions = (new Manager())->getImplicitPermissionsForUser(Gateway::AdminUser()->id);
        $hasBranchIds = [];
        foreach ($userPermissions as $permission) {
            if ('p' . $currentRoutePermission->id === $permission[1]) {
                $hasBranchIds[] = substr($permission[2], 1);
            }
        }
        return $hasBranchIds;
    }

    private static function getHasBranchForeignKeyModels()
    {
        $database = config('database.connections.mysql.database');
        $tables = DB::table('information_schema.COLUMNS')
            ->where(['TABLE_SCHEMA' => $database])
            ->where(['COLUMN_NAME' => 'branch_id'])
            ->select('TABLE_NAME')->get();
        return $tables->map(function ($item) {
            return 'Modules\Common\Models\\' . Str::studly(Str::singular($item->TABLE_NAME));
        })->all();
    }
}
